#include "Game.h"

#include <SFML/Graphics.hpp>

#include "InputManager.h"
#include "TextureCache.h"
#include "Player.h"
#include "Config.h"

#define SAFE_DELETE(p) \
    { \
    if(p) \
        delete p; \
        p = NULL; \
    }


Game::Game()
: m_running(false)
, m_window(NULL)
, m_inputManager(NULL)
, m_player(NULL)
{
    Init();
}

Game::~Game()
{
    Cleanup();
}

bool Game::Init()
{
    m_window =  new sf::RenderWindow(sf::VideoMode(Config::kWindowWidth, Config::kWindowHeigth, Config::kWindowBpp), "Guantelete");
    if(m_window)
    {
        m_window->setFramerateLimit(Config::kFps);
        m_window->setKeyRepeatEnabled(false);
    }

    m_inputManager = new InputManager();
    if(!m_inputManager)
        return false;

    TextureCache::GetInstance();

    m_player = new Player(Config::kWindowWidth / 2, Config::kWindowHeigth / 2);
    if(!m_player)
        return false;

    return true;
}

void Game::Cleanup()
{
    SAFE_DELETE(m_player);

    TextureCache::Destroy();

    SAFE_DELETE(m_inputManager);

    if(m_window && m_window->isOpen())
    {
        m_window->close();
    }
    SAFE_DELETE(m_window);
}

void Game::Run()
{
    sf::Clock clock;

    m_running = true;
    sf::Int32 deltaTime = 0;;
    while(m_running)
    {
        sf::Time timeStart = clock.getElapsedTime();
        Update(deltaTime);
        Render();
        sf::Time timeEnd = clock.restart();
        deltaTime = (timeEnd - timeStart).asMilliseconds();
    }
}

void Game::Update(int deltaTime)
{
    m_inputManager->BeginNewFrame();

    sf::Event event;
    while (m_window->pollEvent(event))
    {
        switch (event.type)
        {
        case sf::Event::Closed:
            m_running = false;
            break;
        case sf::Event::KeyPressed:
            m_inputManager->PressKey(event.key.code);
            break;
        case sf::Event::KeyReleased:
            m_inputManager->ReleaseKey(event.key.code);
            break;
        default:
            break;
        }
    }

    // Handle input
    if(m_inputManager->IsKeyPressed(sf::Keyboard::Escape))
    {
        m_running = false;
    }

    // Handle movement.
    // TODO: All this code should go into InputManager, which will handle input and return a unitary movement "vector"
    bool isLeftHeld = m_inputManager->IsKeyHeld(sf::Keyboard::Left);
    bool isRightHeld = m_inputManager->IsKeyHeld(sf::Keyboard::Right);
    bool isUpHeld = m_inputManager->IsKeyHeld(sf::Keyboard::Up);
    bool isDownHeld = m_inputManager->IsKeyHeld(sf::Keyboard::Down);

    if ((!isLeftHeld && !isRightHeld && !isUpHeld && !isDownHeld) ||    // no movement keys pressed
        ((isLeftHeld && isRightHeld) || (isUpHeld && isDownHeld)))      // opposite directions pressed
    {
        m_player->StopMoving();
    }
    else 
    {
        // TODO: This prioritizes input keys in an arbitrary order. Need to prioritize last pressed keys
        if (isLeftHeld)
        {
            m_player->StartMovingLeft();
        }
        else if (isRightHeld)
        {
            m_player->StartMovingRight();
        }
        else if (isUpHeld)
        {
            m_player->StartMovingUp();
        }
        else if (isDownHeld)
        {
            m_player->StartMovingDown();
        }

    }

    m_player->Update(deltaTime);
}

void Game::Render()
{
    m_window->clear();

    m_player->Render(*m_window);

    m_window->display();
}
